package nobnak.study.gl;

import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import android.R.bool;

public class BezierCurveBuilder {
	private float threatholdDistance;
	
	// Constructors
	public BezierCurveBuilder(float threathold) {
		this.threatholdDistance = threathold;
	}
	
	// Interfaces
	public static interface BezierCurve {
		float[] tessellate();
	}
	
	// Methods
	public BezierCurve makeBezierCurve(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) {
		final List<Float> curve = new ArrayList<Float>();
		curve.add(x0);
		curve.add(y0);
		pushBezierPoints(curve, x0, y0, x1, y1, x2, y2, x3, y3);
		curve.add(x3);
		curve.add(y3);
		return new BezierCurve() {
			@Override
			public float[] tessellate() {
				float[] result = new float[curve.size()];
				int index = 0;
				for (Iterator<Float> iter = curve.iterator(); iter.hasNext(); )
					result[index++] = iter.next();
				return result;
			}
		};
	}
	
	private void pushBezierPoints(List<Float> curve, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) {
		final float INV_TWO = 0.5f;
		
		float x01 = (x0 + x1) * INV_TWO, y01 = (y0 + y1) * INV_TWO;
		float x12 = (x1 + x2) * INV_TWO, y12 = (y1 + y2) * INV_TWO;
		float x23 = (x2 + x3) * INV_TWO, y23 = (y2 + y3) * INV_TWO;
		float x012 = (x01 + x12) * INV_TWO, y012 = (y01 + y12) * INV_TWO;
		float x123 = (x12 + x23) * INV_TWO, y123 = (y12 + y23) * INV_TWO;
		float x0123 = (x012 + x123) * INV_TWO, y0123 = (y012 + y123) * INV_TWO;
		
		float dx03 = x3 - x0, dy03 = y3 - y0;
		float d1 = Math.abs((x1 - x0) * dy03 - (y1 - y0) * dx03);
		float d2 = Math.abs((x2 - x3) * dy03 - (y2 - y3) * dx03);
		
		boolean terminal = ((d1 + d2) * (d1 + d2)) < (threatholdDistance * (dx03 * dx03 + dy03 * dy03));
		
		if (!terminal)
			pushBezierPoints(curve, x0, y0, x01, y01, x012, y012, x0123, y0123);
		curve.add(x0123);
		curve.add(y0123);
		if (!terminal)
			pushBezierPoints(curve, x0123, y0123, x123, y123, x23, y23, x3, y3);
	}
}
